<?php

namespace app\adminapi\controller;

use app\helpers\Common;
use app\libs\exception\ParameterException;
use app\libs\traits\ApiResponse;

use think\facade\Db;
use think\facade\Cache;
use think\facade\Config;
use think\facade\Lang;
use think\Request;
use think\Exception;
use app\BaseController;

class Base extends BaseController
{
    use ApiResponse;

    const MSG_SUCCESS = '请求成功';
    const MSG_ERROR = '请求失败';
    const NOT_DATA = '暂无数据';
    const NOT_PARAM = '缺少参数';

    const STATUS_SUCCESS = 1;
    const STATUS_ERROR = 0;
    const STATUS_NOTICE = 2;
    const CODE_AUTHFAIL = 401;

    const SOURCE_UI_1 = 'element';
    const SOURCE_UI_2 = 'arco-design';

    protected $admin;
    protected $appName = 'common'; // App Name
    protected $model; // 模型对象
    protected $modelName; // 模型名
    protected $defaultWhere = []; // Default where
    protected $defaultField = '*'; // Default field
    protected $defaultOrder = 'created_at DESC'; // Default order
    protected $primaryKey = 'id'; // primaryKey
    protected $columns = []; // columns

    protected $sourceUi = ''; // UI 框架

    protected function initialize()
    {
        $request = $this->request;
        $param = $request->param();
        /*
        if (empty($param['token'])) {
            throw new ParameterException([
                'msg' => 'token 不能为空！'
            ]);
        }

        try {
            $jwtToken = new \app\common\service\Token();
            $checkToken = $jwtToken->checkToken($param['token']);
            if ($checkToken['code'] == 1) {
                throw new ParameterException([
                    'msg' => $checkToken['msg']
                ]);
            }
        } catch (Exception $e) {
            throw new ParameterException([
                'msg' => $e->getMessage()
            ]);
        }
        */

        $this->sourceUi = $request->header('sourceUi');

        $pathinfo = $request->pathinfo();
        $allowAction = ['auth', 'setting/config'];
        if (in_array($pathinfo, $allowAction)) {
            return;
        }

        $token = $request->header('token');
        if (!$token) {
            $token = $param['token'] ?? ''; // 调试用
        }
        if (!$token) {
            throw new ParameterException([
                'code' => self::CODE_AUTHFAIL,
                'msg' => 'token 不能为空！'
            ]);
        }
        /*
        $origin = $request->header('origin');
        if (strstr($origin, 'http://127.0.0.1') !== false || strstr($origin, 'http://localhost') !== false || $param['token']) {
            // TODO 用 token ，只能登录一次
            //$admin = Admin::where('id', $token)->field('*')->find();
            $admin = Admin::where('token', $token)->field('*')->find();
            if (!$admin) {
                throw new ParameterException([
                    'code' => self::CODE_AUTHFAIL,
                    'msg' => 'token值不正确，请重新登录！'
                ]);
            }
            // 超过一天退出登录
            if ($admin['token_expire'] < time()) {
                throw new ParameterException([
                    'code' => self::CODE_AUTHFAIL,
                    'msg' => 'token值已过期，请重新登录！'
                ]);
            }
        } else {
            // 记住密码
            $cookie_admin = cookie('admin');
            if ($cookie_admin) {
                if (!session('admin')) {
                    session('admin', json_decode($cookie_admin, true));
                }
            }
            $admin = session('admin');
            if (!$admin || $admin['token'] !== $token) {
                throw new ParameterException([
                    'code' => self::CODE_AUTHFAIL,
                    'msg' => 'token值不正确，请重新登录！',
                ]);
            }
            if ($admin['token_expire'] < time()) {
                throw new ParameterException([
                    'code' => self::CODE_AUTHFAIL,
                    'msg' => 'token值已过期，请重新登录！'
                ]);
            }
        }
        */
        $jwt_data = \app\common\service\AuthToken::verify($token);
        if (is_array($jwt_data) && isset($jwt_data['msg'])) {
            throw new ParameterException([
                'code' => self::CODE_AUTHFAIL,
                'msg' => $jwt_data['msg'],
            ]);
        }
        if (!$jwt_data || !$jwt_data->admin_id) {
            throw new ParameterException([
                'code' => self::CODE_AUTHFAIL,
                'msg' => '登录状态已过期！',
            ]);
        }
        $admin = cache('auth_admin_id-' . $jwt_data->admin_id);
        if (!$admin) {
            throw new ParameterException([
                'code' => self::CODE_AUTHFAIL,
                'msg' => 'token值已过期，请重新登录！'
            ]);
        }

        $this->admin = $admin;

        $langSet = strtolower($this->admin['lang'] ?? 'zh-cn');
        // 加载应用公共语言包 及 验证语言包
        Lang::load([
            root_path() . 'app/admin/lang/' . $langSet . '/common.php',
            root_path() . 'app/admin/lang/' . $langSet . '/validation.php',
        ]);
    }

    /**
     * List
     */
    public function list(Request $request)
    {
        $param = $request->param();

        $page = 1;
        $limit = 20;
        if (!empty($param['page'])) {
            $page = (int)$param['page'];
        }
        if (!empty($param['limit'])) {
            $limit = (int)$param['limit'];
        }
        $sort_field = $param['sort_field'] ?? '';
        $sort_value = $param['sort_value'] ?? '';

        $className = '\\app\\' . $this->appName . '\\model\\' . $this->modelName;
        $model = new $className;
        $field = $this->defaultField;
        $where = $this->getFilterWhere($request);
        if ($this->defaultWhere) {
            $where = array_merge($this->defaultWhere, $where);
        }
        if ($this->defaultOrder) {
            $order = $this->defaultOrder;
        }
        if ($sort_field && $sort_value) {
            $order = [$sort_field => $sort_value];
        }

//        $data = $model->where($where)->field($field)->order($order)->limit($page, $limit)->select();
//        $count = $model->where($where)->count();
        $data = $model->where($where)->field($field)->order($order)->paginate(['page' => $page, 'list_rows' => $limit]);
        $data = json_decode(json_encode($data), true);
        $list = &$data['data'];
        if ($list) {
            // 处理列表数据
            $list = $this->handleListData($list);
        }

        return api_response(self::STATUS_SUCCESS, '', $data);
    }

    /**
     * Info
     */
    public function info(Request $request)
    {
        $param = $request->param();
        if (empty($param['id'])) {
            return api_response(self::STATUS_ERROR, self::NOT_PARAM, '');
        }

        $id = $param['id'];
        $className = '\\app\\' . $this->appName . '\\model\\' . $this->modelName;
        $model = new $className;
        $info = $model->find($id);
        if (!$info) {
            return api_response(self::STATUS_ERROR, '不存在！', []);
        }
        $info = $model->formatItem($info, ['format_source' => 'backend']);

        return api_response(self::STATUS_SUCCESS, '', $info);
    }

    /**
     * Save
     */
    public function save(Request $request)
    {
        Db::startTrans();
        try {
            $className = '\\app\\' . $this->appName . '\\model\\' . $this->modelName;
            $model = new $className;

            $data = $this->evalData($request);
            if (isset($data['id']) && $data['id']) {
                //$info = $model->where('id', $data['id'])->field('id')->find();
                $info = $model->where('id', $data['id'])->field('*')->find();
                if (!$info) {
                    return api_response(self::STATUS_ERROR, '不存在', '');
                }
                $data['updated_at'] = time();
                $message = '保存失败';
                $result = $model->where(['id' => $data['id']])->update($data);

                $afterAction = '_after_update';
            } else {
                $data['created_at'] = time();
                $message = '创建失败';
                $result = $model->create($data);
                $data['id'] = $result->id ?? 0;

                $afterAction = '_after_insert';
            }
            if ($result === false) {
                return api_response(self::STATUS_ERROR, $message, []);
            }

            // Query执行后的操作
            $model->$afterAction($data);
            if (isset($info)) {
                $afterRes = $this->afterUpdate($data, $info);
            } else {
                $afterRes = $this->afterInsert($data);
            }
            if ($afterRes['code'] != 1) {
                return api_response(self::STATUS_ERROR, $afterRes['msg'] ?? 'after error', []);
            }

            Db::commit();
            return api_response(self::STATUS_SUCCESS, self::MSG_SUCCESS, $data);
        } catch (Exception $e) {
            Db::rollback();
            return api_response(self::STATUS_ERROR, '失败', $e->getMessage());
        }
    }

    /**
     * Delete
     */
    public function delete(Request $request)
    {
        $param = $request->param();
        if (empty($param['id']) && empty($param['ids'])) {
            return api_response(self::STATUS_ERROR, self::NOT_PARAM, '');
        }

        Db::startTrans();
        try {
            $className = '\\app\\' . $this->appName . '\\model\\' . $this->modelName;
            $model = new $className;
            if (isset($param['ids']) && $param['ids']) {
                $ids = (array)$param['ids'];
            } else {
                $ids = (array)$param['id'];
            }
            foreach ($ids as $id) {
                $where = [
                    ['id', '=', $id]
                ];
                $info = $model->where($where)->field('*')->find();
                if (!$info) {
                    Db::rollback();
                    return api_response(self::STATUS_ERROR, '不存在', '');
                }
                if (method_exists($model, 'isUsed')) {
                    // 是否被使用
                    $usedInfo = $model->isUsed($id);
                    if ($usedInfo['code'] == 0) {
                        Db::rollback();
                        return api_response(self::STATUS_ERROR, $usedInfo['msg'], '');
                    }

                    if ($usedInfo['code'] == 1) {
                        //$result = $info->delete();
                        $result = $model->doDelete($id);
                    } elseif ($usedInfo['code'] == 2) {
                        $info->status = config('constants.SOFT_DELETE_STATUS');
                        $result = $info->save();
                    }
                } else {
                    //$result = $info->delete();
                    $result = $model->doDelete($id);
                }
                if ($result === false) {
                    Db::rollback();
                    return api_response(self::STATUS_ERROR, 'Error', '');
                }

                // Query执行后的操作
                $model->_after_delete($info ?? $id);
                $afterRes = $this->afterDelete($info ?? ['id' => $id]);
                if ($afterRes['code'] != 1) {
                    return api_response(self::STATUS_ERROR, $afterRes['msg'] ?? 'after error', []);
                }
            }

            Db::commit();
            return api_response(self::STATUS_SUCCESS, self::MSG_SUCCESS, $model->getlastsql());
        } catch (Exception $e) {
            Db::rollback();
            return api_response(self::STATUS_ERROR, '失败', $e->getMessage());
        }
    }

    /**
     * 操作
     */
    public function handle(Request $request)
    {
        $param = $request->param();
        if (empty($param['id']) && empty($param['ids'])) {
            return api_response(self::STATUS_ERROR, self::NOT_PARAM, '');
        }
        if (!isset($param['status'])) {
            return api_response(self::STATUS_ERROR, '操作类型(status)不能为空', self::NOT_PARAM);
        }

        Db::startTrans();
        try {
            $className = '\\app\\' . $this->appName . '\\model\\' . $this->modelName;
            $model = new $className;
            if (isset($param['ids']) && $param['ids']) {
                $ids = (array)$param['ids'];
            } else {
                $ids = (array)$param['id'];
            }
            foreach ($ids as $id) {
                $where = [
                    ['id', '=', $id]
                ];
                $info = $model->where($where)->field('*')->find();
                if (!$info) {
                    Db::rollback();
                    return api_response(self::STATUS_ERROR, '不存在', '');
                }
                if ($param['status'] == config('constants.SOFT_DELETE_STATUS')) {
                    if (method_exists($model, 'isUsed')) {
                        // 是否被使用
                        $usedInfo = $model->isUsed($id);
                        if ($usedInfo['code'] == 0) {
                            Db::rollback();
                            return api_response(self::STATUS_NOTICE, $usedInfo['msg'], '');
                        }

                        if ($usedInfo['code'] == 1) {
                            $result = $info->delete();
                        } elseif ($usedInfo['code'] == 2) {
                            $info->status = config('constants.SOFT_DELETE_STATUS');
                            $result = $info->save();
                        }
                    } else {
                        //$result = $info->delete();
                        $result = $model->doDelete($id);
                    }
                } else {
                    $info->status = $param['status'];
                    $result = $info->save();
                }
                if ($result === false) {
                    Db::rollback();
                    return api_response(self::STATUS_ERROR, '失败', '');
                }

                $param['id'] = $id;
                $afterRes = $this->afterHandle($param, $info);
                if ($afterRes['code'] != 1) {
                    return api_response(self::STATUS_ERROR, $afterRes['msg'] ?? 'after error', []);
                }
            }

            Db::commit();
            return api_response(self::STATUS_SUCCESS, self::MSG_SUCCESS, '');
        } catch (Exception $e) {
            Db::rollback();
            return api_response(self::STATUS_ERROR, '失败', $e->getMessage());
        }
    }

    /**
     * 更新排序
     */
    public function listOrders(Request $request)
    {
        $param = $request->param();
        if (empty($param['ids'])) {
            return api_response(self::STATUS_ERROR, 'ID(ids)不能为空', self::NOT_PARAM);
        }
        if (!isset($param['sorting'])) {
            return api_response(self::STATUS_ERROR, '排序值(sorting)不能为空', self::NOT_PARAM);
        }

        Db::startTrans();
        try {
            $ids = (array)$param['ids'];
            $sortField = 'sorting';
            $fields = (array)$param[$sortField];
            $className = '\\app\\' . $this->appName . '\\model\\' . $this->modelName;
            $model = new $className;

            $result = true;
            foreach ($ids as $key => $id) {
                $data[$sortField] = $fields[$key];
                $res = $model->where('id', $id)->update($data);
                if ($res === false) {
                    $result = false;
                    break;
                }
            }
            if ($result === false) {
                Db::rollback();
                return api_response(self::STATUS_ERROR, '失败', '');
            }

            Db::commit();
            return api_response(self::STATUS_SUCCESS, self::MSG_SUCCESS, '');
        } catch (Exception $e) {
            Db::rollback();
            return api_response(self::STATUS_ERROR, '失败', $e->getMessage());
        }
    }

    /**
     * 检查名称是否已存在
     */
    public function checkName(Request $request)
    {
        $param = $request->param();
        if (empty($param['name'])) {
            return api_response(self::STATUS_ERROR, self::NOT_PARAM, '');
        }

        $name = $param['name'];
        $className = '\\app\\' . $this->appName . '\\model\\' . $this->modelName;
        $model = new $className;
        $where = [
            ['name', '=', $name],
            ['status', '<>', config('constants.SOFT_DELETE_STATUS')]
        ];
        $info = $model->where($where)->field('id')->find();
        if ($info) {
            return api_response(self::STATUS_SUCCESS, '存在！', []);
        } else {
            return api_response(self::STATUS_ERROR, '不存在！', []);
        }
    }

    /**
     * Eval data for post data save
     *
     * @param Request $request
     * @return array
     */
    protected function evalData($request)
    {
        $data = $request->param();
        unset($data['created_at'], $data['updated_at']);
        // 去掉文件上传字段file
        unset($data['file']);

        return $data;
    }

    /**
     * 数据验证
     */
    protected function validateData($data)
    {
        $validateName = '\\app\\' . $this->appName . '\\validate\\' . $this->modelName;
        if (class_exists($validateName)) {
            $validate = new $validateName;
            $validateRes = $validate->check($data);
            if (!$validateRes) {
                throw new Exception($validate->getError());
            }
        }
    }

    /**
     * 处理列表数据
     */
    protected function handleListData($data)
    {
//        $className = '\\app\\' . $this->appName . '\\model\\' . $this->modelName;
//        $model = new $className;
//
//        $data = $model->formatDatas($data, ['format_source' => 'backend']);

        return $data;
    }

    /**
     * 筛选条件
     */
    protected function getFilterWhere($request)
    {
        $where = [];

        return $where;
    }

    /**
     * 默认条件
     */
    protected function getDefaultWhere()
    {
        $defaultWhere = [
            //['status', '<>', config('constants.SOFT_DELETE_STATUS')] // model 全局的查询范围
        ];

        return $defaultWhere;
    }

    protected function afterInsert($data)
    {
        // 写入日志
        $content = '添加了一条' . __($this->modelName) . '数据。';
        $logRes = Common::actionLog(request(), $this->admin['id'], $content, $data['id'], json_encode([$data]));
        if ($logRes === false) {
            return ['code' => 0, 'msg' => '写入日志失败'];
        }

        return ['code' => 1, 'msg' => ''];
    }

    protected function afterUpdate($data, $info = [])
    {
        // 写入日志
        $content = '更新了一条' . __($this->modelName) . '数据。';
        $logRes = Common::actionLog(request(), $this->admin['id'], $content, $data['id'], json_encode([$data, $info]));
        if ($logRes === false) {
            return ['code' => 0, 'msg' => '写入日志失败'];
        }

        return ['code' => 1, 'msg' => ''];
    }

    protected function afterDelete($data)
    {
        // 写入日志
        $content = '删除了一条' . __($this->modelName) . '数据。';
        $logRes = Common::actionLog(request(), $this->admin['id'], $content, $data['id'], json_encode([$data]));
        if ($logRes === false) {
            return ['code' => 0, 'msg' => '写入日志失败'];
        }

        return ['code' => 1, 'msg' => ''];
    }

    protected function afterHandle($data, $info = [])
    {
        // 写入日志
        $content = '操作了一条' . __($this->modelName) . '数据。';
        $logRes = Common::actionLog(request(), $this->admin['id'], $content, $data['id'], json_encode([$data, $info]));
        if ($logRes === false) {
            return ['code' => 0, 'msg' => '写入日志失败'];
        }

        return ['code' => 1, 'msg' => ''];
    }
}

?>
